package org.artifact.core.plugin.dispatcher;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.hutool.setting.Setting;
import org.artifact.core.constant.ArtifactErrorCode;
import org.artifact.core.context.packet.IPacket;
import org.artifact.core.context.packet.IPacketInterceptor;
import org.artifact.core.context.session.ISession;
import org.artifact.core.exception.AbstractArtifactException;
import org.artifact.core.exception.ArtifactExceptionUtil;
import org.artifact.core.lang.IModule;
import org.artifact.core.lang.IPlugin;
import org.artifact.core.lang.IServer;
import org.artifact.core.lang.MapPlus;
import org.artifact.core.plugin.ioc.IocPlugin;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;

public class DispatcherPlugin implements IPlugin {
	
	static final Log log = LogFactory.get(DispatcherPlugin.class);

	/** 模块集 */
	private Map<Integer,IModule> modules = new HashMap<>();

	/** 拦截器 */
	private IPacketInterceptor interceptor;

	/** 配置 */
	private DispatcherPluginConfig config;

	public DispatcherPlugin() {
		Map config = IServer.me().getContext().getConfig();
		Map dispatcher = MapPlus.get("plugins.dispatcher",config);
		this.config = BeanUtil.mapToBean(dispatcher, DispatcherPluginConfig.class,false);

		// 拦截器
		if (StrUtil.isNotBlank(this.config.getInterceptor())){
			this.interceptor = ReflectUtil.newInstance(this.config.getInterceptor());
		}
	}

	public DispatcherPlugin(DispatcherPluginConfig config) {
		this.config = config;
	}
	
	public void disp(ISession session,IPacket packet) {
		TimeInterval timer = DateUtil.timer();
		try {
			boolean bool = (interceptor!=null && interceptor.handler(session,packet));
			if(!bool){
				Consumer<IPacket> consumer = module(session,packet);
				if(consumer != null){
					consumer.accept(packet);
				}
			}
		} catch (Exception e) {
			packet.getBody().clear();
			if (e instanceof AbstractArtifactException) {
				packet.setStatus(((AbstractArtifactException) e).getCode());
			}else {
				packet.setStatus(ArtifactErrorCode.UNKNOWN_ERROR);
				log.error(e);
			}
			session.sendPacket(packet);
		}  finally {
			// 记录执行时间
			log.debug("commandId : {} execute time : {}",packet.getCmd(), timer.interval());
		}
	}
	
	public Consumer<IPacket> module(ISession session,IPacket packet) {
		IModule module = modules.get(packet.getModuleId());
		ArtifactExceptionUtil.isTrue(ArtifactErrorCode.NOT_FOND_ACTION, module == null);
		return module.disp(session, packet);
	}

	@Override
	public boolean start() {
		try {
			// 扫描包
			scanPackage();

			return true;
		} catch (Exception e) {
			log.error(e);
		}
		return false;
	}

	@Override
	public boolean stop() {
		return true;
	}

	private void scanPackage(){
		Set<Class<?>> clazzs = ClassUtil.scanPackageBySuper(config.getScanPackage(), IModule.class);
		for (Class<?> clazz : clazzs) {
			if(ClassUtil.isNormalClass(clazz)) {
				IModule module = IServer.me().getPlugins().getIPlugin(IocPlugin.class).getService(clazz);
				modules.put(module.getModuleId(),module);
			}
		}
	}
}
